#ifndef LINEMESH_H
#define LINEMESH_H

#include "GfxModel.h"

#include <vector>

// Purpose: Generates a mesh with a given thickness over a line of connected
//          points, e.g., the limbs of a skeleton. The mesh has to be
//          re-generated each time the underlying points are moved.
// Status:  Currently this is not very usable, as it is not integrated with the
//          GfxModel class. The thing to consider is the fact that (as shown
//          in the LineMesh::draw() method) a LineMesh can be drawn as a simple
//          TriangleStrip, which is very efficient. Perhaps the GfxModel class
//          could be changed to at least allow LineStrips to be included, if not
//          used as a replacement for the current implementation, which is a bit
//          cruddy.
//          Integration with a Skeleton class would likely also be required.

class LineMesh
{
	std::vector<Point*> m_pPoints;
	Scalar              m_fSize;
	std::vector<Vertex> m_Vertices;
public:
	
	//TODO: Could have MeshGenerators, which take custom data and generate a
	//      common GfxMesh structure
	
	LineMesh( Scalar fSize ) : m_fSize( fSize ) {}
	
	//TODO: Need a way to populate the m_pPoints array.
	
	void generate()
	{
		//Algorithm to generate a mesh over a line of connected points with a
		// specified width (m_fSize) everywhere
		
		//First calculate the positions of the vertices
		
		int iNumSegs = m_pPoints.size() - 1;
		//NOTE: There will be a total of 2*iNumSegs + 2 vertices
		m_Vertices.resize( 2*iNumSegs + 2 );
		Vector vSegDir;
		Vector vSegNormalDir;
		Vertex newVert;
		
		//Calculate the first two vertices
		vSegDir = (m_pPoints[1]->vPos - m_pPoints[0]->vPos).getUnitVector();
		vSegNormalDir = vSegDir.getNormal();
		newVert.vPos = m_pPoints[0]->getPos() - m_fSize*(vSegDir+vSegNormalDir);
		m_Vertices[0] = newVert;
		newVert.vPos = m_pPoints[0]->getPos() - m_fSize*(vSegDir-vSegNormalDir);
		m_Vertices[1] = newVert;
		
		//Calculate the middle vertices
		for (int i=1;i<iNumSegs;++i) {
		    Vector vOldSegDir = vSegDir;
		    vSegDir = (m_pPoints[i+1]->getPos() -
			                            m_pPoints[i]->getPos()).getUnitVector();
		    Vector vSegDiff = vOldSegDir - vSegDir;
		    if ( 0 == vSegDiff )
				vSegDiff = vOldSegDir.getNormal();
		    Vector vMediator = vSegDiff * m_fSize /
			                                (vOldSegDir.getNormal() % vSegDiff);
		    
		    newVert.vPos = m_pPoints[i]->getPos() - vMediator;
			m_Vertices[2*i] = newVert;
			newVert.vPos = m_pPoints[i]->getPos() + vMediator;
			m_Vertices[2*i+1] = newVert;
		}
		
		//Calculate the last two vertices
		vSegDir = (m_pPoints[iNumSegs]->getPos() -
		                          m_pPoints[iNumSegs-1]->getPos()).UnitVector();
		vSegNormalDir = vSegDir.getNormal();
		newVert.vPos = m_pPoints[iNumSegs]->getPos() + m_fSize * (vSegDir - vSegNormalDir);
		m_Vertices[2*iNumSegs] = newVert;
		newVert.vPos = m_pPoints[iNumSegs]->getPos() + m_fSize * (vSegDir + vSegNormalDir);
		m_Vertices[2*iNumSegs+1] = newVert;
		
		//Now calculate the texture coordinates
		
		VertexList::iterator itVertex;
		for ( itVertex = m_Vertices.begin(), int i = 0;
		      itVertex != m_Vertices.end();
		      ++itVertex, ++i ) {
			int iEven = i % 2;
			//TODO: Check what effect the "- 2" has
			itVertex->vTexCoord = Vector( (double)(i - iEven) /
			                           (double)(iNumVerts - 2), (double)iEven );
		}
	}
	
	//TODO: This is OpenGL-specific and is here for demonstration purposes only.
	//      The final design should probably make use of the ability to include
	//      TriangleStrips in the generic GfxModel data structure, which can
	//      then be rendered efficiently by the specific implementation of
	//      IRenderer::draw( GfxModel ).
	void draw()
	{
		//TODO: Adjust this
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
	    
	    //glBindTexture(GL_TEXTURE_2D, m_gluiTexture);
	    glBindTexture(GL_TEXTURE_2D, 0);
	    
	    //Drawing is super-simple, m_Vertices is just a triangle-strip
	    glBegin(GL_TRIANGLE_STRIP);
	        
	        VertexList::iterator itVertex;
			for ( itVertex = m_Vertices.begin();
			      itVertex != m_Vertices.end();
			      ++itVertex ) {
				
				glTexCoord2dv( itVertex->vTexCoord.getArray() );
	        	glVertex3dv( itVertex->vPos.getArray() );
			}
	    
	    glEnd();
	}
};

#endif //LINEMESH
